package com.ellison.zookeeperdemo.barrier;

import org.I0Itec.zkclient.ZkClient;
import org.junit.Test;

import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 适用场景：
 *  一个业务需要同时，调用多个接口时，
 *  此时不仅要求  `异步执行`
 *       还要求  要有执行完通知
 *
 */
public class BarrierDemo {
    private static String barriepath = "/barrier";

    ZkClient zkClient = new ZkClient("119.3.228.104:2181");

    @Test
    public void test() throws InterruptedException {
        init();
        for (int i = 0; i < 10; i++) {
            task("task" + i,new Random().nextInt(20));
        }
        monitor();
        Thread.currentThread().join();
    }

    private void init() {
        if (!zkClient.exists(barriepath)) {
            //value值就是有几个异步任务
            zkClient.createPersistent(barriepath, 10);
        }
        lister();
    }

    //模拟所有接口的异步调用
    private void task(String nodeName, int loop) {
        CompletableFuture.runAsync(() -> {
            //业务执行时间
            for (int i = 0; i < loop; i++) {
                System.out.println(nodeName + "-->" + (loop - i));
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("=========" + nodeName + "========任务完成，开始创建临时有序节点");
            zkClient.createEphemeralSequential(barriepath + "/" + nodeName, "");
        });
    }

    //监控父节点中子节点个数
    private void monitor() throws InterruptedException {
        Integer nodeNum = (Integer) zkClient.readData(barriepath);
        while (true) {
            List<String> children = zkClient.getChildren(barriepath);
            if (nodeNum == children.size()) {
                zkClient.createEphemeral(barriepath + "/start", "");
                break;
            }
            TimeUnit.MILLISECONDS.sleep(100);
        }
    }

    private void lister() {
        zkClient.subscribeChildChanges(barriepath + "/start", ((parentPath, currentChilds) -> {
            if(parentPath.equals(barriepath + "/start")) {
                System.out.println("===========发送邮件给xx老师===========全部任务做完了=========");
                System.exit(1);
            }
        }));
    }
}
